package com.example.javatool.recallfile;

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class FileMD5Calculator {
    /**
     * 计算指定目录下所有文件的 MD5 值，并将结果追加保存到指定文件中。
     *
     * @param directoryPath  要计算 MD5 值的目录路径
     * @param outputFilePath 保存 MD5 结果的文件路径
     * @throws IOException              当文件操作出错时抛出
     * @throws NoSuchAlgorithmException 当不支持 MD5 算法时抛出
     */
    public static void calculateAndSaveMD5(String directoryPath, String outputFilePath) throws IOException, NoSuchAlgorithmException {
        Path directory = Paths.get(directoryPath);
        if (!Files.isDirectory(directory)) {
            throw new IllegalArgumentException(directoryPath + " 不是一个有效的目录");
        }

        MessageDigest md = MessageDigest.getInstance("MD5");

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilePath, true))) {
            Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    if (Files.isRegularFile(file)) {
                        String md5 = calculateFileMD5(file, md);
                        String fileName = file.getFileName().toString();
                        writer.write(fileName + " " + md5);
                        writer.newLine();
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        }
    }

    /**
     * 计算单个文件的 MD5 值。
     *
     * @param file 要计算 MD5 值的文件路径
     * @param md   MessageDigest 实例，用于计算 MD5
     * @return 文件的 MD5 值的十六进制字符串表示
     * @throws IOException 当文件读取出错时抛出
     */
    private static String calculateFileMD5(Path file, MessageDigest md) throws IOException {
        try (InputStream is = Files.newInputStream(file)) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);
            }
            byte[] digest = md.digest();
            return bytesToHex(digest);
        } finally {
            md.reset();
        }
    }

    /**
     * 将字节数组转换为十六进制字符串。
     *
     * @param bytes 要转换的字节数组
     * @return 十六进制字符串表示
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }

    public static void main(String[] args) {
        // 指定多个目录路径
        String[] directoryPaths = {
                "D:\\email\\服务器已有",
                "D:\\email\\附件",
//                "D:\\email\\outlookfile\\陈珏溢\\附件",
//                "D:\\email\\outlookfile\\陈珊珊\\附件",
//                "D:\\email\\outlookfile\\林琳\\附件",
//                "D:\\email\\outlookfile\\陆敏蔚\\附件",
//                "D:\\email\\outlookfile\\孟连\\附件",
//                "D:\\email\\outlookfile\\孙可欣\\附件",
//                "D:\\email\\outlookfile\\赵志堃\\附件",
//                "D:\\email\\outlookfile\\庄丽珠\\附件",

        };
        String outputFilePath = "D:\\email\\mail_file_md5.txt";
        try {
            Path path = Path.of(outputFilePath);
            if (Files.exists(path)) {
                System.out.println("文件已存在，删除文件：" + outputFilePath);
                Files.delete(path);
            }
            for (String directoryPath : directoryPaths) {
                System.out.println("执行目录：" + directoryPath);
                calculateAndSaveMD5(directoryPath, outputFilePath);
            }
            System.out.println("MD5 计算完成，结果已保存到 " + outputFilePath);
        } catch (IOException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}
